/*
 * Autor: Ewa Byra
 * Zadania ze zjazdu 1
 * PJWSTK
 */
package Z1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

class MyFiles extends File {
	
	private static final long serialVersionUID = 1L;
	private List<File> files;
	private List<File> directores;

	public MyFiles(String pathname) {
		super(pathname);
		files = new ArrayList<File>();
		directores = new ArrayList<File>();
	}

	void fillFiles(File[] f) {
		for (int i = 0; i < f.length; i++)
			if (f[i].isFile())
				files.add(f[i]);
	}

	void fillDirectores(File[] f) {
		for (int i = 0; i < f.length; i++) {
			if (f[i].isDirectory() && f[i].getName().charAt(0) != '.')
				directores.add(f[i]);
		}
	}

	void clearLists() {
		files.clear();
		directores.clear();
	}

	/*
	 * ZADANIE 1, max 3 punkty. Zwracającą listę plików w danym katalogu i
	 * wszystkich jego podkatalogach (rekursywnie): List<File>
	 * listFilesRecurse() List<File> listFilesRecurse(FileNameFilter)
	 */
	List<File> listFilesRecurse() {
		clearLists();
		fillFiles(this.listFiles());
		fillDirectores(this.listFiles());
		for (int i = 0; i < directores.size(); i++) {
			files.addAll(new MyFiles(directores.get(i).getPath())
					.listFilesRecurse());
		}
		return files;
	}

	List<File> listFilesRecurse(FilenameFilter f) {
		clearLists();
		fillFiles(this.listFiles(f));
		fillDirectores(this.listFiles());
		for (int i = 0; i < directores.size(); i++) {
			files.addAll(new MyFiles(directores.get(i).getPath())
					.listFilesRecurse(f));
		}
		return files;
	}

	/*
	 * ZADANIE 2, max 2 punkty. J.w. ale zwracającą listę katalogów
	 * (rekursywnie): List<File> listDirsRecurse() List<File>
	 * listDirsRecurse(FileNameFilter)
	 */
	List<File> listDirsRecurse() {
		clearLists();
		fillDirectores(this.listFiles());
		for (int i = 0; i < directores.size(); i++) {
			directores.addAll(new MyFiles(directores.get(i).getPath())
					.listDirsRecurse());
		}
		return directores;
	}

	List<File> listDirsRecurse(FilenameFilter f) {
		clearLists();
		fillDirectores(this.listFiles(f));
		for (int i = 0; i < directores.size(); i++) {
			directores.addAll(new MyFiles(directores.get(i).getPath())
					.listDirsRecurse(f));
		}
		return directores;
	}

	/*
	 * ZADANIE 3, max 1 punkty. Usuwającą katalog (w przypadku niepustego
	 * katalogu pobierz jego zawartosc, skasuj poszczegolne pozycje, a na koncu
	 * - jest on juz pusty - skasuj go samego): void deleteDir()
	 */
	void deleteDir() {
		clearLists();
		try{
		if (this.listFiles().length != 0) {
			fillFiles(this.listFiles());
			for (File f : files)
				f.delete();
			fillDirectores(this.listFiles());
			for (File d:directores) {
				if (d.listFiles().length == 0)
					d.delete();
				else {
					new MyFiles(d.getPath()).deleteDir();
					d.delete();
				}
			}
			this.delete();
		} else
			this.delete();
		}
		catch(NullPointerException e){
			System.out.println("Nie ma katalogu "+this.getPath());
			e.getStackTrace();
		}
	}

	/*
	 * Kopiującą plik (jesli obecnie wskazana sciezka nie jest katalogiem lub
	 * kopiowanie z jakichkolwiek przyczyn sie nie udalo to zwraca false):
	 * boolean copyFile(String newName) boolean copyFile(String newName, boolean
	 * preserveTime) - ta metoda moze w nowoutworzonym pliku ustawic czas
	 * utworzenia dokladnie taki sam jak w pliku zrodlowym
	 * 
	 * Parametr “newName” - jest to pelna sciezka do nowego pliku znajdujacego
	 * sie w tej samej lub innej lokalizacji.
	 */
	boolean copyFile(String newName) throws IOException {
		boolean result = false;
		FileInputStream in = null;
		FileOutputStream out = null;

		try {
			in = new FileInputStream(this);
			out = new FileOutputStream(newName);
			int c = 0;
			while ((c = in.read()) != -1)
				out.write(c);

		} catch (FileNotFoundException exc) {
			exc.getStackTrace();

		} catch (IOException exc) {
			exc.getStackTrace();

		} finally {
			result = true;
			in.close();
			out.close();
		}
		return result;
	}

	boolean copyFile(String newName, boolean preserveTime) {
		boolean result = false;
		FileChannel srcChannel = null;
		FileChannel dstChannel = null;
		File f = new File(newName);
		try {
			srcChannel = new FileInputStream(this).getChannel();
			dstChannel = new FileOutputStream(f).getChannel();
			dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
			srcChannel.close();
			dstChannel.close();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (preserveTime)
				f.setLastModified(this.lastModified());
			// SimpleDateFormat sdf = new
			// SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
			// System.out.println("data kopiowanego: " +
			// sdf.format(this.lastModified())
			// + "\ndata skopiowanego: " + sdf.format(f.lastModified()));
			result = true;
		}
		return result;
	}

}

/**
 * @author ewa
 *
 */
/**
 * @author ewa
 *
 */
public class TestMyFiles {
	public static void main(String[] args) {
		MyFiles mf = new MyFiles("/home/ewa/Strony internetowe");
		List<File> list = new ArrayList<File>();

		list = mf.listFilesRecurse();
		System.out.println("Test metody listFilesRecurse():");
		for (File l : list)
			System.out.println(l.getPath());

		FilenameFilter f = new FileListFilter("logo");
		list = mf.listFilesRecurse(f);
		System.out.println("\nTest metody listFilesRecurse(FilnameFilter):");
		for (File l : list)
			System.out.println(l.getPath());

		list = mf.listDirsRecurse();
		System.out.println("\nTest metody listDirsRecurse():");
		for (File l : list)
			System.out.println(l.getPath());

		f = new FileListFilter("Strona");
		list = mf.listDirsRecurse(f);
		System.out.println("\nTest metody listDirsRecurse(FilnameFilter):");
		for (File l : list)
			System.out.println(l.getPath());

		System.out.println("\nTest metody deleteDir():");
		mf = new MyFiles("/home/ewa/do skasowania");
		mf.deleteDir();

		System.out.println("\nTest metody copy():");
		mf = new MyFiles(
				"/home/ewa/PJWSTK/ALG - Algebra Liniowa i Geomeria/Wykłady/Wyklad1ALG2002wie.doc");
		try {
			mf.copyFile("/home/ewa/PJWSTK/ALG - Algebra Liniowa i Geomeria/Wykłady/test.doc");
			mf.copyFile("/home/ewa/Dokumenty/test.doc", true);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

class FileListFilter implements FilenameFilter {
	private String name, extension;

	public FileListFilter(String name, String extension) {
		this.name = name;
		this.extension = '.' + extension;
	}

	public FileListFilter(String name) {
		this.name = name;
		this.extension = "";
	}

	public boolean accept(File directory, String filename) {
		boolean fileOK = true;

		if (name != "")
			fileOK &= filename.startsWith(name);
		if (extension != "")
			fileOK &= filename.endsWith(extension);

		return fileOK;
	}
}